#include "orangepch.h"
#include "WindowsWindow.h"
#include <GLFW/glfw3.h>
#include <glad/glad.h>

#include <stdio.h>
// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
#endif

static void glfw_error_callback(int error, const char *description)
{
    fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}

namespace Orange
{
    static bool s_GLFWinitlized = false;

    Window *Window::Create(const WindowProps &props)
    {
        return new WindowsWindow(props);
    }

    WindowsWindow::WindowsWindow(const WindowProps &props)
    {
        Init(props);
    }

    WindowsWindow::~WindowsWindow()
    {
    }
    void WindowsWindow::Init(const WindowProps &props)
    {

        m_Data.m_Width = props.Width;
        m_Data.m_Height = props.Height;
        m_Data.m_Title = props.Title;
        glfwSetErrorCallback(glfw_error_callback);
        if (!s_GLFWinitlized)
        {
            int success = glfwInit();
            if (!success)
            {
                std::cout << "Could not intialize GLFW!" << std::endl;
                ORANGE_CORE_ERROR("Could not intialize GLFW!");
                return;
            }
        }

#if defined(__APPLE__)

        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);           // Required on Mac
                                                                       // 3.0+ only
#endif

        ORANGE_CORE_INFO("Create Window");
        m_Window = glfwCreateWindow((int)m_Data.m_Width, (int)m_Data.m_Height, m_Data.m_Title.c_str(), nullptr, nullptr);
        glfwSetWindowUserPointer(m_Window, &m_Data);

        glfwMakeContextCurrent(m_Window);
        SetVSync(true);

        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
        {
            std::cout << "Failed to initialize GLAD" << std::endl;
            return;
        }

        ORANGE_CORE_INFO("Opengl info:");
        ORANGE_CORE_INFO("vendor: {0}", glGetString(GL_VENDOR));
        ORANGE_CORE_INFO("renderer: {0}", glGetString(GL_RENDERER));
        ORANGE_CORE_INFO("version: {0}", glGetString(GL_VERSION));

        // 窗口关闭
        glfwSetWindowCloseCallback(m_Window, [](GLFWwindow *window)
                                   {
                                       WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);
                                       WindowCloseEvent e;
                                       data.Callback(e); });
        // 文本流输入
        glfwSetCharCallback(m_Window, [](GLFWwindow *window, uint32_t code)
                            {
                                WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);
                                KeyTypedEvent e(code);
                                data.Callback(e); });
        // 窗口改变
        glfwSetWindowSizeCallback(m_Window, [](GLFWwindow *window, int width, int height)
                                  {
                                      WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);
                                      WindowResizeEvent e(width, height);
                                      data.Callback(e); });
        // 按键事件
        glfwSetKeyCallback(m_Window, [](GLFWwindow *window, int key, int scancode, int action, int mods)
                           {
                               WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);

                               switch (action)
                               {
                               case GLFW_PRESS:
                               {
                                   KeyPressedEvent e(key, 0);
                                   data.Callback(e);
                                   break;
                               }
                               case GLFW_RELEASE:
                               {
                                   KeyReleasedEvent e(key);
                                   data.Callback(e);
                                   break;
                               }
                               case GLFW_REPEAT:
                               {
                                   KeyPressedEvent e(key, 1);
                                   data.Callback(e);
                                   break;
                               }
                               } });

        // 鼠标滚轮事件

        glfwSetScrollCallback(m_Window, [](GLFWwindow *window, double xoffset, double yoffset)
                              {
                                  WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);
                                  MouseScrolledEvent e((float)xoffset, (float)yoffset);
                                  data.Callback(e); });

        // 鼠标移动事件

        glfwSetCursorPosCallback(m_Window, [](GLFWwindow *window, double xpos, double ypos)
                                 {
                                     WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);
                                     MouseMovedEvent e((float)xpos, (float)ypos);
                                     data.Callback(e); });

        // 鼠标点击事件

        glfwSetMouseButtonCallback(m_Window, [](GLFWwindow *window, int button, int action, int mods)
                                   {
                                       WindowData &data = *(WindowData *)glfwGetWindowUserPointer(window);

                                       switch (action)
                                       {
                                       case GLFW_PRESS:
                                       {
                                           MouseButtonPressedEvent e(button);
                                           data.Callback(e);
                                           break;
                                       }

                                       case GLFW_RELEASE:
                                       {
                                           MouseButtonReleasedEvent e(button);
                                           data.Callback(e);
                                           break;
                                       }
                                       } });
    }

    void WindowsWindow::OnUpdate()
    {
        glfwPollEvents();

        glfwSwapBuffers(m_Window);
    }

    uint32_t WindowsWindow::GetWidth() const
    {
        return m_Data.m_Width;
    }

    uint32_t WindowsWindow::GetHeight() const
    {
        return m_Data.m_Height;
    }

    void WindowsWindow::SetVSync(bool enable)
    {
        if (enable)
        {
            glfwSwapInterval(1);
        }
        else
        {
            glfwSwapInterval(0);
        }
        m_Data.Vsync = enable;
    };
    bool WindowsWindow::IsVSync() const
    {
        return m_Data.Vsync;
    };

    // 获取当前窗口
    void *WindowsWindow::GetNativeWindow() const
    {
        return m_Window;
    };

    void WindowsWindow::ShutDown()
    {
        glfwDestroyWindow(m_Window);
    };

}